package com.xunmall.executors.framework;

import com.xunmall.executors.framework.policy.CountableRejectedExecutionHandler;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author wangyj03@zenmen.com
 * @description 自定义的增强型线程池，增加监控、动态调用参数服辅助功能
 *              核心的任务执行、线程调度直接复用原有的线程池功能
 * @date 2020/9/28 16:24
 */
public class EnhancedThreadPoolExecutor extends ThreadPoolExecutor {

    private String name;

    private boolean monitorEnable = true;

    private List<String> monitorCodes = new ArrayList<String>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isMonitorEnable() {
        return monitorEnable;
    }

    public void setMonitorEnable(boolean monitorEnable) {
        this.monitorEnable = monitorEnable;
    }

    public List<String> getMonitorCodes() {
        return monitorCodes;
    }

    public void setMonitorCodes(List<String> monitorCodes) {
        this.monitorCodes = monitorCodes;
    }

    public EnhancedThreadPoolExecutor(int corePoolSize,
                                      int maximumPoolSize,
                                      long keepAliveTime,
                                      BlockingQueue<Runnable> workQueue,
                                      ThreadFactory threadFactory,
                                      RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, handler);
    }

    public void update(int coreSize,int maxSize,int keepAliveSeconds,int queueSize,ThreadFactory threadFactory,RejectedExecutionHandler rejectedExecutionHandler,boolean monitorEnable,List<String> monitorCodes){
        setCorePoolSize(coreSize);
        setMaximumPoolSize(maxSize);
        setKeepAliveTime(keepAliveSeconds,TimeUnit.SECONDS);
        setThreadFactory(threadFactory);
        setRejectedExecutionHandler(rejectedExecutionHandler);
        setMonitorEnable(monitorEnable);
        setMonitorCodes(monitorCodes);
    }

    public ExecutorStats stats(){
        int activeThreadLoad = getActiveCount() * 100 / getMaximumPoolSize();
        int taskCompletionRate = getTaskCount() == 0 ? 0 : (int)(getCompletedTaskCount() * 100 / getTaskCount());
        int queueSize = getQueue().size();
        long rejectedCount =((CountableRejectedExecutionHandler) getRejectedExecutionHandler()).count();
        return new ExecutorStats(activeThreadLoad,taskCompletionRate,queueSize,rejectedCount);
    }

    /***
     * @Description: [Executor 线程池的运行状态]
     * @Title:
     * @Author: WangYanjing
     * @Date: 2020/9/28
     * @Param: null
     * @Return: null
     * @Throws:
     */
    public static class ExecutorStats {
        private int activeThreadLoad;

        private int taskCompletionRate;

        private int queueSize;

        private long rejectedCount;

        public ExecutorStats(int activeThreadLoad, int taskCompletionRate, int queueSize, long rejectedCount) {
            this.activeThreadLoad = activeThreadLoad;
            this.taskCompletionRate = taskCompletionRate;
            this.queueSize = queueSize;
            this.rejectedCount = rejectedCount;
        }

        public int getActiveThreadLoad() {
            return activeThreadLoad;
        }

        public void setActiveThreadLoad(int activeThreadLoad) {
            this.activeThreadLoad = activeThreadLoad;
        }

        public int getTaskCompletionRate() {
            return taskCompletionRate;
        }

        public void setTaskCompletionRate(int taskCompletionRate) {
            this.taskCompletionRate = taskCompletionRate;
        }

        public int getQueueSize() {
            return queueSize;
        }

        public void setQueueSize(int queueSize) {
            this.queueSize = queueSize;
        }

        public long getRejectedCount() {
            return rejectedCount;
        }

        public void setRejectedCount(long rejectedCount) {
            this.rejectedCount = rejectedCount;
        }
    }
}
